/**
 * Created by TamTT on 1/13/14.
 * FPT University - Da Nang
 * Capstone project - group 3
 * Jornee
 */
module.exports.controller = function(app, jwt, secret, db, authentication, util, async, io, log, colors){
	var mongojs = require('mongojs');
	var gcm = require('node-gcm');

	/**
	 * Search friend function - TamTT
	 */
	app.post('/search_friend', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var keyword = req.body.keyword;
				var my_id = result.login_user;

				db.users.find({
					$and: [
						{
							username: keyword
						},
						{
							username: {
								$ne: my_id
							}
						}
					]
				}, {
					_id: 0,
					username: 1,
					avatar: 1
				}, function(err, exact_users){
					if(err){
						log.error('Search friend - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					} else {
						db.users.find({
							$and: [
								{
									username: {
										$regex: keyword
									}
								},
								{
									username: {
										$ne: my_id
									}
								},
								{
									username: {
										$ne: keyword
									}
								}
							]
						}, {
							_id: 0,
							username: 1,
							avatar: 1
						}).limit(10, function(err, regex_users){
								if(err){
									log.error('Search friend - User %s - Error with %s'.red, my_id, err);
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								} else {
									var doc = exact_users.concat(regex_users);
									var result = [];
									async.each(doc, function(each, callback){
										db.users.find({
											username: my_id,
											following: {
												$in: [each.username]
											}
										}, function(err, doc2){
											if(err){
												log.error('Search friend - User %s - Error with %s'.red, my_id, err);
												res.send({
													authen_status: 'ok',
													status: 'error'
												});
											}
											if(doc2.length > 0){
												result.push({
													username: each.username,
													following: 'true',
													avatar: "" + each.avatar
												});
											} else {
												result.push({
													username: each.username,
													following: 'false',
													avatar: "" + each.avatar
												});
											}
											callback();
										});
									}, function(err){
										if(err){
											log.error('Search friend - User %s - Error with %s'.red, my_id, err);
											res.send({
												authen_status: 'ok',
												status: 'error'
											});
										}
										log.info('Search friend - User %s - Ok'.blue, my_id);
										res.send({
											authen_status: 'ok',
											status: 'ok',
											result: result
										});
									});
								}
							}
						);
					}
				});
			}
		});
	});

	/**
	 * Follow function - TamTT
	 * Add my id to friend follower, add friend's id to my following
	 * Add all public journeys of friend to my outside
	 * Add directly share to me journey of friends to my outside
	 * Send in-app notification if friend online, or system notification if not
	 * If user already follow friend before, no notification will be sent. This is for anti spam purpose
	 */
	app.post('/follow', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				var friend_id = req.body.friend_id;
				var date = new Date().toISOString();
				if(my_id === friend_id){
					log.error('Follow - User %s - You cannot follow yourself. If you see this, we got some serious problems!'.red, my_id);
					res.send({
						authen_status: 'ok',
						status: 'error'
					});
				} else {
					db.users.update({
						username: my_id
					}, {
						$push: {
							following: friend_id
						}
					}, function(err){
						if(err){
							log.error('Follow - User %s - Error with %s'.red, my_id, err);
							res.send({
								authen_status: 'ok',
								status: 'error'
							});
						} else {
							db.users.update({
								username: friend_id
							}, {
								$addToSet: {
									follower: my_id
								}
							}, function(err){
								if(err){
									log.error('Follow - User %s - Error with %s'.red, my_id, err);
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								} else {
									log.info('Follow - User %s - Ok'.blue, my_id);
									res.send({
										authen_status: 'ok',
										status: 'ok'
									});
								}
							});
							//Check if this action was acted before (Anti spam)
							db.notification.findOne({
								user_id: friend_id,
								'notification.other_id': my_id,
								'notification.type': 'follow'
							}, {
								_id: 1
							}, function(err, notification){
								if(err){
									log.error('Follow - User %s - Error with %s'.red, my_id, err);
								} else if(!notification){
									//Check if user is online, send in-app notification. If not, send system notification
									db.users.findOne({
										username: friend_id
									}, {
										_id: 0,
										chat_id: 1
									}, function(err, user){
										if(err || !user){
											log.error('Follow - User %s - Error with %s'.red, my_id, err || 'No user');
											io.sockets.socket(user.chat_id).emit('error', {
												message: 'fail'
											});
										} else {
											if(user.chat_id && user.chat_id != ''){
												//In-app notification
												log.info('Follow - User %s - %s is online. Send in-app notification'.blue, my_id, friend_id);
												io.sockets.socket(user.chat_id).emit('server_noti', {
													other_id: my_id,
													type: "follow",
													content_id: my_id,
													time: date
												});
											} else {
												//System notification
												log.info('Follow - User %s - %s is offline. Send GCM notification'.blue, my_id, friend_id);
												sendNoti({
													my_id: friend_id,
													other_id: my_id,
													type: 'follow',
													content_id: my_id,
													time: date
												});
											}
											//Update notification into database
											db.notification.update({
												user_id: friend_id
											}, {
												$push: {
													notification: {
														other_id: my_id,
														type: "follow",
														content_id: my_id,
														time: date
													}
												},
												$inc: {
													unread_noti: 1
												}
											}, {
												upsert: true
											}, function(err){
												if(err){
													log.error('Follow - User %s - Error with %s'.red, my_id, err);
												}
											});
										}
									});
								}
							});
						}
					});
				}

				//Add friend's public journey to my outside
				//Add directly share to you journey of friends to your outside
				db.journey.find({
					user_id: friend_id,
					$or: [
						{
							'shared.type': 'public'
						},
						{
							'shared.ids': my_id
						}
					]
				}, {
					_id: 1
				}, function(err, journeys){
					if(err){
						log.error('Follow - User %s - Error with %s'.red, my_id, err);
					}
					if(!err && journeys && journeys.length > 0){
						var journey_ids = [];
						journeys.forEach(function(journey){
							journey_ids.push(journey._id);
						});
						db.users.update({
							username: my_id
						}, {
							$push: {
								outside: {
									$each: journey_ids
								}
							}
						}, function(err){
							if(err){
								log.error('Follow - User %s - %s follow %s . Update journeys error : %s'.red, my_id, my_id, friend_id, err);
							}
						});
					}
				})

			}
		});
	});

	/**
	 * Unfollow function - TamTT
	 * Remove all journeys of friend out of my outside
	 */
	app.post('/unfollow', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				var friend_id = req.body.friend_id;
				if(my_id === friend_id){
					res.send({
						authen_status: 'ok',
						status: 'error'
					});
				} else {
					db.users.update({
						username: my_id
					}, {
						$pull: {
							following: friend_id
						}
					}, function(err){
						if(err){
							log.error('Unfollow - User %s - Error with %s'.red, my_id, err);
							res.send({
								authen_status: 'ok',
								status: 'error'
							});
						} else {
							db.users.update({
								username: friend_id
							}, {
								$pull: {
									follower: my_id
								}
							}, function(err){
								if(err){
									log.error('Unfollow - User %s - Error with %s'.red, my_id, err);
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								} else {
									log.info('Unfollow - User %s - Ok'.blue, my_id);
									res.send({
										authen_status: 'ok',
										status: 'ok'
									});
								}
							});
						}
					});
				}
				//Remove all journey of friend out of my outside
				db.journey.find({
					user_id: friend_id,
					$or: [
						{
							'shared.type': 'public'
						},
						{
							'shared.ids': my_id
						}
					]
				}, {
					_id: 1
				}, function(err, journeys){
					if(err){
						log.error('Unfollow - User %s - Error with %s'.red, my_id, err);
					}
					if(!err && journeys && journeys.length > 0){
						var journey_ids = [];
						journeys.forEach(function(journey){
							journey_ids.push(journey._id);
						});
						db.users.update({
							username: my_id
						}, {
							$pullAll: {
								outside: journey_ids
							}
						}, function(err){
							if(err){
								log.error('Unfollow - User %s - %s unfollow %s . Update journeys error : %s'.red, my_id, my_id, friend_id, err);
							}
						});
					}
				})
			}
		});
	});

	/**
	 * View follow function - TamTT
	 */
	app.post('/view_follow', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				if(req.body.username === undefined){
					var user_id = result.login_user;
				} else {
					var user_id = req.body.username;
				}
				//Find the user following and follower list
				db.users.findOne({
					username: user_id
				}, {
					_id: 0,
					follower: 1,
					following: 1
				}, function(err, user_list){
					if(err){
						log.error('View follow - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					} else if(!user_list){
						res.send({
							authen_status: 'ok',
							status: 'fail'
						});
					} else {
						if(user_list.follower === undefined){
							user_list.follower = [];
						}
						//Get users in my follower list to get username and avatar
						db.users.find({
							username: {
								$in: user_list.follower
							}
						}, {
							_id: 0,
							username: 1,
							avatar: 1
						}, function(err, user_followers){
							if(err){
								log.error('View follow - User %s - Error with %s'.red, my_id, err);
								res.send({
									authen_status: 'ok',
									status: 'error'
								});
							} else {
								//Find my following and follower list
								db.users.findOne({
									username: my_id
								}, {
									_id: 0,
									follower: 1,
									following: 1
								}, function(err, my_list){
									if(err){
										log.error('View follow - User %s - Error with %s'.red, my_id, err);
										res.send({
											authen_status: 'ok',
											status: 'error'
										});
									} else {
										if(my_list.following === undefined){
											my_list.following = [];
										}
										//Check if I'm following user followers
										async.each(user_followers, function(follower, callback){
											var index = my_list.following.indexOf(follower.username); //Check if his name is in my following list
											var index2 = user_followers.indexOf(follower); //Get the position
											if(follower.username === my_id){
												user_followers[index2].following = 'not';
												callback();
											} else if(index > -1){
												//I'm following him
												user_followers[index2].following = 'true';
												callback();
											} else {
												//I am not
												user_followers[index2].following = 'false';
												callback();
											}
										}, function(err){
											if(err){
												log.error('View follow - User %s - Error with %s'.red, my_id, err);
												res.send({
													authen_status: 'ok',
													status: 'error'
												});
											}
											if(my_list.following === undefined){
												my_list.following = [];
											}
											//Add avatar to my following list
											db.users.find({
												username: {
													$in: user_list.following
												}
											}, {
												_id: 0,
												username: 1,
												avatar: 1
											}, function(err, user_followings){
												if(err){
													log.error('View follow - User %s - Error with %s'.red, my_id, err);
													res.send({
														authen_status: 'ok',
														status: 'error'
													});
												} else {
													async.each(user_followings, function(folowing, callback){
														var index = my_list.following.indexOf(folowing.username); //Check if his name is in my following list
														var index2 = user_followings.indexOf(folowing); //Get the position
														if(folowing.username === my_id){
															user_followings[index2].following = 'not';
															callback();
														} else if(index > -1){
															//I'm following him
															user_followings[index2].following = 'true';
															callback();
														} else {
															//I am not
															user_followings[index2].following = 'false';
															callback();
														}
													}, function(err){
														if(err){
															log.error('View follow - User %s - Error with %s'.red, my_id, err);
															res.send({
																authen_status: 'ok',
																status: 'error'
															});
														}
														log.info('View follow - User %s - Ok'.blue, my_id);
														res.send({
															authen_status: 'ok',
															status: 'ok',
															follower: user_followers,
															following: user_followings
														});
													});
												}
											});
										});
									}
								});
							}
						});
					}
				});
			}
		});
	});

	/**
	 * Share journey function
	 */
	app.post('/share_journey', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var journey_id = req.body.journey_id;
				var share_type = req.body.share_type;
				var share_with = req.body.share_with;
				//Find journey and update its shared information
				db.journey.update({
					_id: mongojs.ObjectId(journey_id)
				}, {
					$set: {
						shared: {
							type: share_type,
							ids: share_with,
							date: new Date()
						}
					}
				}, function(err){
					if(err){
						log.error('Share journey - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					} else {
						db.users.findOne({
							username: my_id
						}, {
							_id: 0,
							follower: 1
						}, function(err, user){
							if(err){
								log.error('Share journey - User %s - Error with %s'.red, my_id, err);
								res.send({
									authen_status: 'ok',
									status: 'error'
								});
							} else {
								if(share_type === 'public'){
									user.follower.forEach(function(follower){
										db.users.update({
											username: follower
										}, {
											$set: {
												$push: {
													outside: mongojs.ObjectId(journey_id)
												}
											}
										});
									});
								} else {
									share_with.follower.forEach(function(follower){
										db.users.update({
											username: follower
										}, {
											$set: {
												$push: {
													outside: mongojs.ObjectId(journey_id)
												}
											}
										});
									});
								}
								log.info('Share journey - User %s - Ok'.red, my_id);
								res.send({
									authen_status: 'ok',
									status: 'ok'
								});
							}
						})
					}
				});
			}
		});
	});

	/**
	 * View outside - TamTT
	 * I follow and un-follow people: add or remove their journey from my outside, set reload to 'true'
	 * People share journey to me: add to my outside
	 * People delete their journey: remove from my outside
	 */
	app.post('/outside', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var page = req.body.page;
				//Get outside array from my record
				db.users.findOne({
					username: my_id
				}, {
					_id: 0,
					outside: 1,
					outside_deliver: 1
				}, function(err, user){
					if(err){
						log.error('Outside - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					}
					if(!user){
						log.warning('Outside - User %s - No user'.yellow, my_id);
						res.send({
							authen_status: 'ok',
							status: 'fail'
						});
					} else {
						//If page == 0, then send new journeys from the last position
						if(page == 0){
							var range_top = user.outside_deliver.top;
							//Get all journeys that include in user outside array and sort by shared.date
							db.journey.find({
								_id: {
									$in: user.outside
								},
								'shared.date': {
									$gt: range_top
								}
							}).sort({
									'shared.date': -1
								}).limit(10, function(err, journeys){
									if(err){
										log.error('Outside - User %s - Error with %s'.red, my_id, err);
										res.send({
											authen_status: 'ok',
											status: 'error'
										});
									}
									if(!journeys){
										log.warning('Outside - User %s - No journey'.yellow, my_id);
										res.send({
											authen_status: 'ok',
											status: 'fail'
										});
									} else {
										if(journeys.length > 0){
											db.users.update({
												username: my_id
											}, {
												$set: {
													'outside_deliver.top': journeys[0].shared.date
												}
											});
										}
										async.each(journeys, function(journey, callback){
											db.users.findOne({
												username: journey.user_id
											}, {
												_id: 0,
												avatar: 1
											}, function(err, user){
												if(err){
													log.error('Outside - User %s - Error with %s'.red, my_id, err);
													res.send({
														authen_status: 'ok',
														status: 'error'
													});
												}
												if(!user){
													log.warning('Outside - User %s - No user'.yellow, my_id);
													res.send({
														authen_status: 'ok',
														status: 'fail'
													});
												} else {
													var index = journeys.indexOf(journey);
													journeys[index].create_date = journeys[index].shared.date;
													journeys[index].avatar = user.avatar;
													db.entry.find({
														_id: {
															$in: journey.entries
														}
													}, {
														_id: 0,
														type: 1,
														text: 1,
														path: 1,
														place_id: 1,
														place_name: 1,
														address: 1
													}).sort({
															create_date: -1
														}, function(err, entries){
															if(err){
																log.error('Outside - User %s - Error with %s'.red, my_id, err);
																res.send({
																	authen_status: 'ok',
																	status: 'error'
																});
															}
															if(!entries){
																log.warning('Outside - User %s - No entries'.yellow, my_id);
																var num_of_entries = 0;
															} else {
																var num_of_entries = entries.length;
															}
															if(num_of_entries === 0){
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = 0;
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
																journeys[index].start_point = 'Some Where';
																journeys[index].end_point = 'Some Where';
															} else if(num_of_entries > 0 && num_of_entries < 6){
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = num_of_entries;
																journeys[index].entries = [];
																for(var i = 0; i < entries.length; i++){
																	if(entries[i].type == 'text'){
																		journeys[index].entries.push({
																			type: entries[i].type,
																			data: entries[i].text
																		});
																	} else {
																		journeys[index].entries.push({
																			type: entries[i].type,
																			data: entries[i].path
																		});
																	}
																}
																journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
																journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
															} else {
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = 5;
																journeys[index].entries = [];
																var first_entry = 0; //Index of the first entry to push to array of entries
																var fifth_entry = entries.length - 1; //Index of the fifth entry to push to array of entries
																var third_entry = Math.floor(Math.random() * (fifth_entry - 3)) + 2; //Index of the third entry to push to array of entries
																var second_entry = Math.floor(Math.random() * (third_entry - 2)) + 1;
																var fourth_entry = Math.floor(Math.random() * (fifth_entry - third_entry - 2)) + (third_entry + 1);
																//Push the first entry
																if(entries[first_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[first_entry].type,
																		data: entries[first_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[first_entry].type,
																		data: entries[first_entry].path
																	});
																}
																//Push the second entry
																if(entries[second_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[second_entry].type,
																		data: entries[second_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[second_entry].type,
																		data: entries[second_entry].path
																	});
																}
																//Push the third entry
																if(entries[third_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[third_entry].type,
																		data: entries[third_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[third_entry].type,
																		data: entries[third_entry].path
																	});
																}
																//Push the fourth entry
																if(entries[fourth_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[fourth_entry].type,
																		data: entries[fourth_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[fourth_entry].type,
																		data: entries[fourth_entry].path
																	});
																}
																//Push the fifth entry
																if(entries[fifth_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[fifth_entry].type,
																		data: entries[fifth_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[fifth_entry].type,
																		data: entries[fifth_entry].path
																	});
																}

																journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
																journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
															}
															callback();
														});
												}
											});
										}, function(err){
											if(err){
												log.error('Outside - User %s - Error with %s'.red, my_id, err);
												res.send({
													authen_status: 'ok',
													status: 'error'
												});
											}
											log.info('Outside - User %s - Ok'.blue, my_id);
											res.send({
												authen_status: 'ok',
												status: 'ok',
												journeys: journeys
											});
										});
									}
								})
						} else { //If page != 0
							//If page == 1, reload, send from current datetime
							//If page == 2, send journeys older than the bottom position
							if(page == 1){
								var range_bottom = new Date().toISOString();
							} else if(page == 2){
								var range_bottom = user.outside_deliver.bottom;
							}
							//Get all journeys that include in user outside array and sort by shared.date
							db.journey.find({
								_id: {
									$in: user.outside
								},
								'shared.date': {
									$lt: range_bottom
								}
							}).sort({
									'shared.date': -1
								}).limit(10, function(err, journeys){
									if(err){
										log.error('Outside - User %s - Error with %s'.red, my_id, err);
										res.send({
											authen_status: 'ok',
											status: 'error'
										});
									}
									if(!journeys){
										log.warning('Outside - User %s - No journey'.yellow, my_id);
										res.send({
											authen_status: 'ok',
											status: 'fail'
										});
									} else {
										if(page == 1){
											db.users.update({
												username: my_id
											}, {
												$set: {
													'outside_deliver.top': range_bottom
												}
											});
										}
										if(journeys.length > 0){
											db.users.update({
												username: my_id
											}, {
												$set: {
													'outside_deliver.bottom': journeys[journeys.length - 1].shared.date
												}
											});
										}
										async.each(journeys, function(journey, callback){
											db.users.findOne({
												username: journey.user_id
											}, {
												_id: 0,
												avatar: 1
											}, function(err, user){
												if(err){
													log.error('Outside - User %s - Error with %s'.red, my_id, err);
													res.send({
														authen_status: 'ok',
														status: 'error'
													});
												}
												if(!user){
													log.warning('Outside - User %s - No user'.yellow, my_id);
													res.send({
														authen_status: 'ok',
														status: 'fail'
													});
												} else {
													var index = journeys.indexOf(journey);
													journeys[index].create_date = journeys[index].shared.date;
													journeys[index].avatar = user.avatar;
													db.entry.find({
														_id: {
															$in: journey.entries
														}
													}, {
														_id: 0,
														type: 1,
														text: 1,
														path: 1,
														place_id: 1,
														place_name: 1,
														address: 1
													}).sort({
															create_date: -1
														}, function(err, entries){
															if(err){
																log.error('Outside - User %s - Error with %s'.yellow, my_id, err);
																res.send({
																	authen_status: 'ok',
																	status: 'error'
																});
															}
															if(!entries){
																var num_of_entries = 0;
															} else {
																var num_of_entries = entries.length;
															}
															if(num_of_entries === 0){
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = 0;
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
																journeys[index].start_point = 'Some Where';
																journeys[index].end_point = 'Some Where';
															} else if(num_of_entries > 0 && num_of_entries < 6){
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = num_of_entries;
																journeys[index].entries = [];
																for(var i = 0; i < entries.length; i++){
																	if(entries[i].type == 'text'){
																		journeys[index].entries.push({
																			type: entries[i].type,
																			data: entries[i].text
																		});
																	} else {
																		journeys[index].entries.push({
																			type: entries[i].type,
																			data: entries[i].path
																		});
																	}
																}
																journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
																journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
															} else {
																journeys[index].num_of_all_entries = num_of_entries;
																journeys[index].num_of_return_entries = 5;
																journeys[index].entries = [];
																var first_entry = 0; //Index of the first entry to push to array of entries
																var fifth_entry = entries.length - 1; //Index of the fifth entry to push to array of entries
																var third_entry = Math.floor(Math.random() * (fifth_entry - 3)) + 2; //Index of the third entry to push to array of entries
																var second_entry = Math.floor(Math.random() * (third_entry - 2)) + 1;
																var fourth_entry = Math.floor(Math.random() * (fifth_entry - third_entry - 2)) + (third_entry + 1);
																//Push the first entry
																if(entries[first_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[first_entry].type,
																		data: entries[first_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[first_entry].type,
																		data: entries[first_entry].path
																	});
																}
																//Push the second entry
																if(entries[second_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[second_entry].type,
																		data: entries[second_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[second_entry].type,
																		data: entries[second_entry].path
																	});
																}
																//Push the third entry
																if(entries[third_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[third_entry].type,
																		data: entries[third_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[third_entry].type,
																		data: entries[third_entry].path
																	});
																}
																//Push the fourth entry
																if(entries[fourth_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[fourth_entry].type,
																		data: entries[fourth_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[fourth_entry].type,
																		data: entries[fourth_entry].path
																	});
																}
																//Push the fifth entry
																if(entries[fifth_entry].type == 'text'){
																	journeys[index].entries.push({
																		type: entries[fifth_entry].type,
																		data: entries[fifth_entry].text
																	});
																} else {
																	journeys[index].entries.push({
																		type: entries[fifth_entry].type,
																		data: entries[fifth_entry].path
																	});
																}

																journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
																journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
																journeys[index].liked = journeys[index].liked.length;
																journeys[index].comment = journeys[index].comment.length;
																if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
																	journeys[index].is_liked = 'true';
																} else {
																	journeys[index].is_liked = 'false';
																}
															}
															callback();
														});
												}
											});
										}, function(err){
											if(err){
												log.error('Outside - User %s - Error with %s'.red, my_id, err);
												res.send({
													authen_status: 'ok',
													status: 'error'
												});
											}
											log.info('Outside - User %s - Ok'.blue, my_id);
											res.send({
												authen_status: 'ok',
												status: 'ok',
												journeys: journeys
											});
										});
									}
								}
							)
						}
					}
				});
			}
		});
	});

	/**
	 * View user's profile - TamTT
	 */
	app.post('/user_profile', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				var user_id = req.body.username;
				if(my_id == user_id){
					var is_me = 'true';
				} else {
					var is_me = 'false';
				}
				db.users.findOne({
					username: user_id
				}, {
					_id: 0,
					username: 1,
					gender: 1,
					email: 1,
					dob: 1,
					host: 1,
					avatar: 1,
					follower: 1,
					following: 1
				}, function(err, user){
					if(err){
						log.error('User profile - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					}
					if(!user){
						log.warning('User profile - User %s - No user'.yellow, my_id);
						res.send({
							authen_status: 'ok',
							status: 'fail'
						});
					} else {
						var index = user.follower.indexOf(my_id);
						if(index > -1){
							//I'm following him
							var is_following = 'true';
							res.send({
								authen_status: 'ok',
								status: 'ok',
								username: user.username,
								avatar: user.avatar,
								num_of_follower: user.follower.length,
								num_of_following: user.following.length,
								email: user.email,
								dob: user.dob,
								gender: user.gender,
								is_host: user.host,
								is_me: is_me,
								is_following: is_following
							});
						} else {
							//I am not
							var is_following = 'false';
							res.send({
								authen_status: 'ok',
								status: 'ok',
								username: user.username,
								avatar: user.avatar,
								num_of_follower: user.follower.length,
								num_of_following: user.following.length,
								email: user.email,
								dob: user.dob,
								gender: user.gender,
								is_host: user.host,
								is_me: is_me,
								is_following: is_following
							});
						}

					}
				});
			}
		});
	});

	/**
	 * View user's profile - TamTT
	 */
	app.post('/user_journeys', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var user_id = req.body.username;
				if(my_id == user_id){
					var is_me = 'true';
				} else {
					var is_me = 'false';
				}
				if(is_me === 'true'){
					log.warning('User journeys - User %s - View self-profile '.yellow, my_id);
					var journeys_query = {
						user_id: my_id
					};
				} else {
					log.warning('User journeys - User %s - View %s profile '.yellow, my_id, user_id);
					var journeys_query = {
						user_id: user_id,
						$or: [
							{
								'shared.type': 'public'
							},
							{
								'shared.type': 'specific',
								'shared.ids': my_id
							}
						]
					};
				}
				db.journey.find(journeys_query).sort({
					create_date: -1
				}, function(err, journeys){
					if(err){
						log.error('User journeys - User %s - Error with '.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					}
					log.info('User journeys - User %s - Num of journey found: %s '.blue, my_id, journeys.length);
					db.users.findOne({
						username: user_id
					}, {
						_id: 0,
						avatar: 1
					}, function(err, user){
						if(err){
							log.error('User journeys - User %s - Error with '.red, my_id, err);
							res.send({
								authen_status: 'ok',
								status: 'error'
							});
						}
						if(!user){
							log.warning('User journeys - User %s - No user '.yellow, my_id);
							res.send({
								authen_status: 'ok',
								status: 'fail'
							});
						} else {
							async.each(journeys, function(journey, callback){
								var index = journeys.indexOf(journey);
								journeys[index].avatar = user.avatar;
								db.entry.find({
									_id: {
										$in: journey.entries
									}
								}, {
									_id: 0,
									type: 1,
									text: 1,
									path: 1,
									place: 1
								}).sort({
										create_date: -1
									}, function(err, entries){
										if(err){
											log.error('User journeys - User %s - Error with '.red, my_id, err);
											res.send({
												authen_status: 'ok',
												status: 'error'
											});
										}
										if(!entries){
											var num_of_entries = 0;
										} else {
											var num_of_entries = entries.length;
										}
										if(num_of_entries === 0){
											journeys[index].num_of_all_entries = num_of_entries;
											journeys[index].num_of_return_entries = 0;
											journeys[index].liked = journeys[index].liked.length;
											journeys[index].comment = journeys[index].comment.length;
											if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
												journeys[index].is_liked = 'true';
											} else {
												journeys[index].is_liked = 'false';
											}
											journeys[index].start_point = 'Some Where';
											journeys[index].end_point = 'Some Where';
										} else if(num_of_entries > 0 && num_of_entries < 6){
											journeys[index].num_of_all_entries = num_of_entries;
											journeys[index].num_of_return_entries = num_of_entries;
											journeys[index].entries = [];
											for(var i = 0; i < entries.length; i++){
												if(entries[i].type == 'text'){
													journeys[index].entries.push({
														type: entries[i].type,
														data: entries[i].text
													});
												} else {
													journeys[index].entries.push({
														type: entries[i].type,
														data: entries[i].path
													});
												}
											}
											journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
											journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
											journeys[index].liked = journeys[index].liked.length;
											journeys[index].comment = journeys[index].comment.length;
											if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
												journeys[index].is_liked = 'true';
											} else {
												journeys[index].is_liked = 'false';
											}
										} else {
											journeys[index].num_of_all_entries = num_of_entries;
											journeys[index].num_of_return_entries = 5;
											journeys[index].entries = [];
											var first_entry = 0; //Index of the first entry to push to array of entries
											var fifth_entry = entries.length - 1; //Index of the fifth entry to push to array of entries
											var third_entry = Math.floor(Math.random() * (fifth_entry - 3)) + 2; //Index of the third entry to push to array of entries
											var second_entry = Math.floor(Math.random() * (third_entry - 2)) + 1;
											var fourth_entry = Math.floor(Math.random() * (fifth_entry - third_entry - 2)) + (third_entry + 1);
											//Push the first entry
											if(entries[first_entry].type == 'text'){
												journeys[index].entries.push({
													type: entries[first_entry].type,
													data: entries[first_entry].text
												});
											} else {
												journeys[index].entries.push({
													type: entries[first_entry].type,
													data: entries[first_entry].path
												});
											}
											//Push the second entry
											if(entries[second_entry].type == 'text'){
												journeys[index].entries.push({
													type: entries[second_entry].type,
													data: entries[second_entry].text
												});
											} else {
												journeys[index].entries.push({
													type: entries[second_entry].type,
													data: entries[second_entry].path
												});
											}
											//Push the third entry
											if(entries[third_entry].type == 'text'){
												journeys[index].entries.push({
													type: entries[third_entry].type,
													data: entries[third_entry].text
												});
											} else {
												journeys[index].entries.push({
													type: entries[third_entry].type,
													data: entries[third_entry].path
												});
											}
											//Push the fourth entry
											if(entries[fourth_entry].type == 'text'){
												journeys[index].entries.push({
													type: entries[fourth_entry].type,
													data: entries[fourth_entry].text
												});
											} else {
												journeys[index].entries.push({
													type: entries[fourth_entry].type,
													data: entries[fourth_entry].path
												});
											}
											//Push the fifth entry
											if(entries[fifth_entry].type == 'text'){
												journeys[index].entries.push({
													type: entries[fifth_entry].type,
													data: entries[fifth_entry].text
												});
											} else {
												journeys[index].entries.push({
													type: entries[fifth_entry].type,
													data: entries[fifth_entry].path
												});
											}

											journeys[index].start_point = entries[num_of_entries - 1].place_name || entries[num_of_entries - 1].address || entries[num_of_entries - 1].coordinate || 'Some Where';
											journeys[index].end_point = entries[0].place_name || entries[0].address || entries[0].coordinate || 'Some Where';
											journeys[index].liked = journeys[index].liked.length;
											journeys[index].comment = journeys[index].comment.length;
											if(journey.liked.length > 0 && journey.liked.indexOf(my_id) > -1){
												journeys[index].is_liked = 'true';
											} else {
												journeys[index].is_liked = 'false';
											}
										}
										callback();
									});
							}, function(err){
								if(err){
									log.error('User journeys - User %s - Error with '.red, my_id, err);
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								}
								log.info('User journeys - User %s - Ok - Return: %s'.blue, my_id, util.inspect(journeys,{ showHidden: true, depth: null }));
								res.send({
									authen_status: 'ok',
									status: 'ok',
									journeys: journeys
								});
							});
						}
					});
				});
			}
		});
	});

	/**
	 *
	 * Authentication function for admin only
	 */
	function admin_authentication(req, fn){
		var token = req.body.token;
		db.admin.findOne({
			authentication: token
		}, function(err, result){
			if(err){
				log.error('Admin authen - Error with %s'.red, err);
				fn({
					loginStatus: 'error'
				});
			} else if(result == null){
				log.warning('Admin authen - Wrong token'.yellow);
				fn({
					loginStatus: 'false'
				});
			} else {
				log.info('Admin authen - Admin %s - Ok'.blue, result.username);
				fn({
					loginStatus: 'true',
					login_user: result.username
				});
			}
		});
	}

	/**
	 * Messaging
	 */
	io.set('authorization', function(handshakeData, accept){
		var handshakeToken = {
			body: {
				token: handshakeData.query.token
			}
		};
		if(handshakeData.query.role == 'admin'){
			admin_authentication(handshakeToken, function(result){
				if(result.loginStatus == 'error'){
					accept({
						message: 'error'
					}, false);
				} else if(result.loginStatus == 'false'){
					accept({
						message: 'unauthorized'
					}, false);
				} else if(result.loginStatus == 'true'){
					/**
					 * Code begin
					 */
						//Username: result.login_user
					handshakeData.my_id = result.login_user;
					handshakeData.role = 'admin';
					accept(null, true);
				}
			});
		} else {
			authentication(handshakeToken, function(result){
				if(result.loginStatus == 'error'){
					accept({
						message: 'error'
					}, false);
				} else if(result.loginStatus == 'false'){
					accept({
						message: 'unauthorized'
					}, false);
				} else if(result.loginStatus == 'true'){
					/**
					 * Code begin
					 */
						//Username: result.login_user
					handshakeData.my_id = result.login_user;
					handshakeData.role = 'user';
					accept(null, true);
				}
			});
		}

	});

	io.sockets.on('connection', function(socket){
		if(socket.handshake.role == 'user'){
			var my_id = socket.handshake.my_id;
			db.users.update({
				username: my_id
			}, {
				$set: {
					chat_id: socket.id
				}
			});
			log.info('User %s connected'.blue, my_id);

			socket.on('disconnect', function(){
				db.users.update({
					username: my_id
				}, {
					$set: {
						chat_id: ''
					}
				});
				log.info('User %s disconnected'.blue, my_id);
			});

			socket.on('seen_message', function(data){
				db.chat.update({
					$or: [
						{
							chatters: {
								this_user: my_id,
								that_user: data.other_user
							}
						},
						{
							chatters: {
								this_user: data.other_user,
								that_user: my_id
							}
						}
					]
				}, {
					$set: {
						unread_message: 0
					}
				}, function(err, conversation){
				});
			});

			socket.on('client_message', function(data){
				var date = new Date().toISOString();
				console.log();
				log.info("Received - from: %s to: %s - content: %s - On: %s ".blue, my_id, data.other_user, data.message, date);
				/**
				 * function for add message to conversation
				 * @param conversation
				 */
				function add_chat_lines(conversation){
					db.chat.update({
						_id: conversation._id
					}, {
						$push: {
							conversation: {
								chatter: my_id,
								message: data.message,
								time: date
							}
						},
						$set: {
							modified_date: date
						},
						$inc: {
							unread_message: 1
						}
					}, function(err){
						if(err){
							log.error('Chat - User %s - Error with %s'.red, my_id, err);
							socket.emit('error', {
								message: 'error'
							});
						} else {
							db.users.findOne({
								username: data.other_user
							}, {
								_id: 0,
								chat_id: 1,
								avatar: 1
							}, function(err, user){
								if(err || !user){
									socket.emit('error', {
										message: 'error'
									});
								} else {
									if(user.chat_id && user.chat_id != ''){
										//Emit to that user
										db.users.findOne({
											username: my_id
										}, {
											_id: 0,
											avatar: 1
										}, function(err, myself){
											if(err || !myself){
												socket.emit('error', {
													message: 'error'
												});
											} else {
												io.sockets.socket(user.chat_id).emit('server_message', {
													message: data.message,
													from_user: my_id,
													avatar: myself.avatar,
													time: date
												});
											}
										});
									} else {
										//Send notification if user offline
										sendNoti({
											my_id: data.other_user,
											other_id: my_id,
											type: 'message',
											content_id: '',
											time: date
										});
									}
								}
							});
						}
					});
				} // End function add_chat_lines

				db.chat.findOne({
					$or: [
						{
							chatters: {
								this_user: my_id,
								that_user: data.other_user
							}
						},
						{
							chatters: {
								this_user: data.other_user,
								that_user: my_id
							}
						}
					]
				}, {
					_id: 1
				}, function(err, conversation){
					if(err){
						log.error('Chat - User %s - Error with %s'.red, my_id, err);
						socket.emit('error', {
							message: 'error'
						});
					} else if(!conversation){ //They have never chat before
						db.users.findOne({
								username: data.other_user
							}, {
								_id: 1
							}, //Check if other user is exist
							function(err, user){
								if(err || !user){
									socket.emit('error', {
										message: 'error'
									});
								} else {
									db.chat.save({
										chatters: {
											this_user: my_id,
											that_user: data.other_user
										},
										conversation: []
									}, function(err, conversation){
										if(err){
											socket.emit('error', {
												message: 'error'
											});
										} else {
											add_chat_lines(conversation);
										}
									});
								}
							});
					} else { //They have chatted before
						add_chat_lines(conversation);
					}
				});
			});
		} else {
			log.info('Admin live chart - User %s - Connected'.blue, socket.handshake.my_id);
			socket.on('ticker', function(fn){
				db.users.count({
					chat_id: {
						$ne: ''
					}
				}, function(err, num){
					if(err){
						log.error('Admin live chart - User %s - Error with %s'.red, socket.handshake.my_id, err);
						fn('error');
					} else {
						fn(num);
					}
				});
			});
			socket.on('disconnect', function(){
				log.info('Admin live chart - User %s - Disconnected'.blue, socket.handshake.my_id);
			});
		}
	});

	/**
	 * Conversation detail
	 */
	app.post('/conversation_detail', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var friend_id = req.body.friend_id;
				var page = req.body.page;
				var date = new Date().toISOString();

				//Check if the last message belong to me, the unread_message won't be reset
				db.chat.findOne({
					$or: [
						{
							chatters: {
								this_user: my_id,
								that_user: friend_id
							}
						},
						{
							chatters: {
								this_user: friend_id,
								that_user: my_id
							}
						}
					]
				}, {
					_id: 1,
					conversation: {
						$slice: -1
					}
				}, function(err, conversation){
					if(err){
						log.error('Conversation detail - User %s - Error with %s'.red, my_id, err);
					}
					if(!err && conversation){
						if(conversation.conversation[0].chatter == friend_id){
							db.chat.update({
								_id: conversation._id
							}, {
								$set: {
									unread_message: 0
								}
							});
						}
					}
				});

				/**
				 * Function for get chat lines and set bound to load pages
				 * @param my_id
				 * @param friend_id
				 * @param bound_date
				 */
				function return_chat_lines(my_id, friend_id, bound_date){
					db.chat.aggregate({
						$match: {
							$or: [
								{
									chatters: {
										this_user: my_id,
										that_user: friend_id
									}
								},
								{
									chatters: {
										this_user: friend_id,
										that_user: my_id
									}
								}
							]
						}
					}, {
						$unwind: "$conversation"
					}, {
						$match: {
							"conversation.time": {
								$lt: bound_date
							}
						}
					}, {
						$sort: {
							"conversation.time": -1
						}
					}, {
						$limit: 10
					}, {
						$project: {
							_id: 0,
							conversation: 1
						}
					}, function(err, chat_lines){
						if(err || !chat_lines){
							res.send({
								authen_status: 'ok',
								status: 'fail'
							});
						} else {
							var lines_return = [];
							chat_lines.forEach(function(line){
								lines_return.push(line.conversation);
							});
							if(lines_return.length > 0){
								db.chat.findOne({
									$or: [
										{
											chatters: {
												this_user: my_id,
												that_user: friend_id
											}
										},
										{
											chatters: {
												this_user: friend_id,
												that_user: my_id
											}
										}
									],
									'chatter_deliver.user_id': my_id
								}, {
									_id: 1
								}, function(err, conversation_deliver){
									if(err){
										res.send({
											authen_status: 'ok',
											status: 'fail'
										});
									} else if(!conversation_deliver){
										db.chat.update({
											$or: [
												{
													chatters: {
														this_user: my_id,
														that_user: friend_id
													}
												},
												{
													chatters: {
														this_user: friend_id,
														that_user: my_id
													}
												}
											]
										}, {
											$push: {
												chatter_deliver: {
													user_id: my_id,
													bound: lines_return[lines_return.length - 1].time
												}
											}
										});
									} else {
										db.chat.update({
											$or: [
												{
													chatters: {
														this_user: my_id,
														that_user: friend_id
													}
												},
												{
													chatters: {
														this_user: friend_id,
														that_user: my_id
													}
												}
											],
											'chatter_deliver.user_id': my_id
										}, {
											$set: {
												'chatter_deliver.$.bound': lines_return[lines_return.length - 1].time
											}
										});
									}
								});
							}
							db.users.find({
								username: {
									$in: [my_id, friend_id]
								}
							}, {
								_id: 0,
								username: 1,
								avatar: 1
							}, function(err, users){
								if(err || !users || users.length < 2){
									res.send({
										authen_status: 'ok',
										status: 'fail'
									});
								} else {
									var chatter_return = [];
									users.forEach(function(user){
										chatter_return.push({
											user_id: user.username,
											avatar: user.avatar
										});
									});
									res.send({
										authen_status: 'ok',
										status: 'ok',
										chatters: chatter_return,
										chat_lines: lines_return
									});
								}
							});
						}
					});
				}

				if(page == 1){
					return_chat_lines(my_id, friend_id, date);
				} else if(page == 2){
					db.chat.aggregate({
						$match: {
							$or: [
								{
									chatters: {
										this_user: my_id,
										that_user: friend_id
									}
								},
								{
									chatters: {
										this_user: friend_id,
										that_user: my_id
									}
								}
							]
						}
					}, {
						$unwind: '$chatter_deliver'
					}, {
						$match: {
							'chatter_deliver.user_id': my_id
						}
					}, {
						$project: {
							_id: 0,
							chatter_deliver: 1
						}
					}, function(err, chat_deliver){
						if(err || !chat_deliver){
							res.send({
								authen_status: 'ok',
								status: 'fail'
							});
						} else {
							if(chat_deliver.length > 0){
								return_chat_lines(my_id, friend_id, chat_deliver[0].chatter_deliver.bound);
							} else {
								log.info('Conversation detail - User %s - Ok'.blue, my_id);
								res.send({
									authen_status: 'ok',
									status: 'fail'
								});
							}
						}
					});
				}
			}
		});
	});

	/**
	 * See list of conversation
	 */
	app.post('/list_conversations', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				var skip = req.body.skip || '0';
				//Find all conversation that include mysefl as a chatter
				db.chat.find({
					$or: [
						{
							'chatters.this_user': my_id
						},
						{
							'chatters.that_user': my_id
						}
					]
				}, {
					_id: 0,
					chatters: 1,
					conversation: {
						$slice: -1
					},
					unread_message: 1
				}).sort({
						modified_date: -1
					}).skip(+skip).limit(10, function(err, conversations){
						var list_return = [];
						async.each(conversations, function(conversation, callback){
							var new_conversation = {};
							if(conversation.chatters.this_user == my_id){
								new_conversation.chatter = conversation.chatters.that_user;
							} else {
								new_conversation.chatter = conversation.chatters.this_user;
							}
							new_conversation.last_chatter = conversation.conversation[0].chatter;
							if(conversation.conversation[0].chatter == my_id){
								new_conversation.unread_message = 0;
							} else {
								new_conversation.unread_message = conversation.unread_message;
							}
							new_conversation.last_message = conversation.conversation[0].message;
							new_conversation.time = conversation.conversation[0].time;
							db.users.findOne({
								username: new_conversation.chatter
							}, {
								_id: 0,
								avatar: 1
							}, function(err, user){
								if(err || !user){
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								} else {
									new_conversation.avatar = user.avatar;
									list_return.push(new_conversation);
									callback();
								}
							});
						}, function(err){
							if(err){
								log.error('List conversation - User %s - Error with %s'.red, my_id, err);
								res.send({
									authen_status: 'ok',
									status: 'error'
								});
							} else {
								log.info('List conversation - User %s - Ok'.blue,my_id);
								res.send({
									authen_status: 'ok',
									status: 'ok',
									list: list_return
								});
							}
						})
					});
			}
		});
	});

	/**
	 * Regis device for notification
	 */
	app.post('/noti_register', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var regId = req.body.regId;
				db.notification.update({
					regId: regId
				}, {
					$set: {
						"regId": ''
					}
				}, function(err){
					if(err){
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					} else {
						db.notification.update({
							'user_id': my_id
						}, {
							$set: {
								regId: regId
							}
						}, {
							upsert: true
						}, function(err){
							if(err){
								res.send({
									authen_status: 'ok',
									status: 'error'
								});
							} else {
								console.log("Device register for: " + my_id);
								res.send({
									authen_status: 'ok',
									status: 'ok'
								});
							}
						});
					}
				});
			}
		});
	});

	/**
	 * Unregister device
	 */
	app.post('/noti_unregister', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				var my_id = result.login_user;
				db.notification.update({
					'user_id': my_id
				}, {
					$set: {
						regId: ''
					}
				}, function(err){
					if(err){
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					} else {
						log.info('Device unregister for: '.blue, my_id);
						res.send({
							authen_status: 'ok',
							status: 'ok'
						});
					}
				});
			}
		});
	});

	/**
	 * Clear chat_id each time restart server
	 */
	db.users.update({}, {
		$set: {
			chat_id: ''
		}
	}, {
		multi: true
	}, function(err){
		if(err){
			log.error('Clear chat ID - Result with error: %s'.red, err);
		} else {
			log.info('Clear chat ID - Ok'.blue);
		}
	});

	/**
	 * Function for sending notification
	 * @param content
	 */
	function sendNoti(content){
		// with object values
		var message = new gcm.Message({
			//collapseKey: 'cms',
			delayWhileIdle: true,
			//timeToLive: 10,
			data: {
				other_id: content.other_id,
				type: content.type,
				content_id: content.content_id,
				time: content.time
			}
		});
		var sender = new gcm.Sender('AIzaSyCb-bORk00XZslcplMH3iw9eHYzaHnZav0');
		var registrationIds = [];
		db.notification.findOne({
			user_id: content.my_id
		}, {
			_id: 0,
			regId: 1
		}, function(err, getted){
			if(err){
				log.error('Send notification - User %s - Send to %s -  Result with error: %s'.red, content.other_id, content.my_id, err);
			}
			if(getted && getted.regId){
				registrationIds.push(getted.regId);
				if(registrationIds.length > 0){
					/**
					 * Params: message-literal, registrationIds-array, No. of retries, callback-function
					 **/
					sender.send(message, registrationIds, 10, function(err, result){
						if(err){
							log.error('Send notification - User %s - Send to %s -  Result with error: %s'.red, content.other_id, content.my_id, err);
						} else {
							log.info('Send notification - User %s - Send to %s - Type %s - Result %s'.blue, content.other_id, content.my_id, content.type, util.inspect(result));
						}
					});
				}
			} else {
				log.warning('Send notification - User %s - Send to %s - Type %s -  Result : No registered devices'.yellow, content.other_id, content.my_id, content.type);
			}
		});
	}

	/**
	 * List notification
	 */
	app.post('/list_notification', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var skip = req.body.skip;

				//Reset notification
				db.notification.update({
					user_id: my_id
				}, {
					$set: {
						unread_noti: 0
					}
				});

				db.notification.aggregate({
					$match: {
						user_id: my_id
					}
				}, {
					$unwind: "$notification"
				}, {
					$sort: {
						"notification.time": -1
					}
				}, {
					$match: {
						'notification.type': {
							$ne: 'message'
						}
					}
				}, {
					$skip: +skip
				}, {
					$limit: 10
				}, {
					$project: {
						_id: 0,
						notification: 1
					}
				}, function(err, noties){
					if(err){
						log.error('List notification - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'fail' + err
						});
					} else {
						var noties_return = [];
						async.each(noties, function(noti, callback){
							var noti_return = {};
							noti_return = noti.notification;
							db.users.findOne({
								username: noti.notification.other_id
							}, {
								_id: 0,
								avatar: 1
							}, function(err, user){
								if(err || !user){
									log.error('List notification - User %s - Error with %s'.red, my_id, err || 'No user');
									res.send({
										authen_status: 'ok',
										status: 'error'
									});
								} else {
									noti_return.avatar = user.avatar;
									noties_return.push(noti_return);
									callback();
								}
							});
						}, function(err){
							if(err){
								log.error('List notification - User %s - Error with %s'.red, my_id, err);
								res.send({
									authen_status: 'ok',
									status: 'err'
								});
							} else {
								log.info('List notification - User %s - Ok'.blue, my_id);
								res.send({
									authen_status: 'ok',
									status: 'ok',
									list: noties_return
								});
							}
						});
					}
				});
			}
		});
	});

	/**
	 * List notification
	 */
	app.post('/share_iplace', function(req, res){
		authentication(req, function(result){
			if(result.loginStatus == 'error'){
				res.send({
					authen_status: 'error'
				});
			} else if(result.loginStatus == 'false'){
				res.send({
					authen_status: 'fail'
				});
			} else if(result.loginStatus == 'true'){
				/**
				 * Code begin
				 */
				//Username: result.login_user
				var my_id = result.login_user;
				var entry_id = req.body.entry_id;
				var iplace_name = req.body.iplace_name;
				var category = req.body.category;

				db.entry.findOne({
					_id: mongojs.ObjectId(entry_id)
				}, {
					_id: 0,
					place_id: 1
				}, function(err, entry){
					if(err){
						log.error('Share iplace - User %s - Error with %s'.red, my_id, err);
						res.send({
							authen_status: 'ok',
							status: 'error'
						});
					}
					if(!entry.place_id){
						log.warning('Share iplace - User %s - Entry have no place_id. Entry_id: %s'.yellow, my_id, entry_id);
						res.send({
							authen_status: 'ok',
							status: 'fail'
						});
					} else {
						log.info('Share iplace - User %s - Place_id %s'.blue, my_id, entry.place_id);
						db.interestingplace.findOne({
							place_id: entry.place_id
						}, {
							_id: 1
						}, function(err, iplace){
							if(err){
								log.error('Share iplace - User %s - Error with %s'.red, my_id, err);
								res.send({
									authen_status: 'ok',
									status: 'error'
								});
							}
							if(!iplace){
								log.warning('Share iplace - User %s - No iplace yet, insert new one'.yellow, my_id);
								db.interestingplace.save({
									place_id: entry.place_id,
									category: [category],
									create_date: new Date().toISOString()
								}, function(err, saved_iplace){
									if(err){
										log.error('Share iplace - User %s - Error with %s'.red, my_id, err);
										res.send({
											authen_status: 'ok',
											status: 'error'
										});
									}
									db.entry.update({
										_id: mongojs.ObjectId(entry_id)
									}, {
										$set: {
											iplace_id: saved_iplace._id,
											iplace_name: iplace_name
										}
									}, function(err){
										if(err){
											log.error('Share iplace - User %s - Error with %s'.red, my_id, err);
											res.send({
												authen_status: 'ok',
												status: 'error'
											});
										}
										log.info('Share iplace - User %s - Ok'.blue, my_id);
										res.send({
											authen_status: 'ok',
											status: 'ok'
										});
									});
								})
							} else {
								log.warning('Share iplace - User %s - Already exist, now update: entry %s'.yellow, my_id, entry_id);
								db.interestingplace.update({
									place_id: entry.place_id
								}, {
									$addToSet: {
										category: category
									}
								}, function(err){
									if(err){
										log.error('Share iplace - User %s - Add category %s with error: %s'.red, my_id, category, err);
									}
								});
								db.entry.update({
									_id: mongojs.ObjectId(entry_id)
								}, {
									$set: {
										iplace_id: iplace._id,
										iplace_name: iplace_name
									}
								}, function(err){
									if(err){
										log.error('Share iplace - User %s - Error with %s'.red, my_id, err);
										res.send({
											authen_status: 'ok',
											status: 'error'
										});
									}
									log.info('Share iplace - User %s - Ok'.blue, my_id);
									res.send({
										authen_status: 'ok',
										status: 'ok'
									});
								});
							}
						});
					}
				});
			}
		});
	});

};